
package next_flag_search;

import agents.Agent;
import env.Action;
import env.Enviroment;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author user
 */
public abstract class Search {

    LinkedList<Action> plan = null;
    private Agent agent;
    public int expanded_nodes=0; //"T"
    //int iterations

    public abstract LinkedList<Action> search();
    
    /**
     * a generic search, just plug in a queueing function and you're golden!
     * @param queue
     * @return
     */
    public LinkedList<Action> graphSearch(MyQueue queue) {
        HashSet<Node> closed = new HashSet<Node>();
        Node root=new Node(null, null, 0, 0, getAgent().getRow(), getAgent().getCol(), getAgent().getOrientation());        
        queue.add(root);
        closed.add(root);
        int c = 0, e=0;
        while (!queue.isEmpty()) {
            Node node = queue.poll();
            //goal test
            if (Enviroment.env.map[node.getRow()][node.getCol()].hasFlag()) {
                //System.out.println("@@@@ after " + c + " iteration, search is finished! @@@@");
                //Enviroment.env.drawArrow(getAgent().getRow(), getAgent().getCol(), node.getRow(), node.getCol(), agent.getColor());
                expanded_nodes+=e;
                return node.getActionPath();
            }
            List<Node> expand = node.expand();
            for (Node n : expand) {
                if (!closed.contains(n)) {
                    queue.add(n);
                    closed.add(n);
                    e++;
                }
            }
            c++;
        }

        return null;
    }

    public Action nextAction() {
        if (plan == null || plan.isEmpty()) {
            rePlan();
        }
        return plan != null ? plan.removeFirst() : null;
    }

    public void rePlan() {
        try {
            Thread.sleep(50);
        } catch (InterruptedException ex) {
            Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("before replanning, my performance measure is " + Enviroment.f+"*"+agent.score+" - "+expanded_nodes+" = "+((Enviroment.f * agent.score) - expanded_nodes));
        //Astar: my performance measure is 10*869 - 4484 = 4206
        //BFS:my performance measure is 10*871 - 14854 = -6144
        //IDS:my performance measure is 10*762 - 3092 = 4528
        //IDS:my performance measure is 10*763 - 3091 = 4539


        plan = search();
        System.out.println("my new plan is " + plan + " \npress enter to confirm!");
        try {
            System.in.read();
        } catch (IOException ex) {
            Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
    }

    public Agent getAgent() {
        return agent;
    }

    public void setAgent(Agent agent) {
        this.agent = agent;
    }
}
